A large gap exists between technology designs that are readily understood by people, on the one hand, and working computational technology implementations, on the other. People are most comfortable and fluent with natural languages and visual descriptions in a product design, whereas computational technology is ultimately implemented as bits flowing through circuits. Over several decades the gap between design and implementation has been bridged by using high-level programming languages and their development environments. A software product development cycle generally includes a high-level design, which guides developers in writing software in one or more high-level programming languages, which is then compiled into lower level instructions (possibly by way of intermediate code such as bytecode or assembly language) until instructions are generated that can be executed (possibly after suitable linking and loading operations) by a computing system.
Changing the lower-level instructions poses technical challenges, but some mechanisms do exist to modify lower-level instructions in some ways. For example, one may dynamically load additional instructions through a plug-in or a dynamically loaded library, and one may modify jump tables to swap one function for another as the destination of a function call. Debuggers and profilers insert instructions along a program's execution path to halt execution, or to log when a particular piece of code is executed, for example. Tools may also be used to patch a binary file before it is loaded for execution. Some relatively simple programs also contain self-modifying code. Some types of malware produce copies of themselves as an effect of their execution. Sometimes changes to low-level instructions are undesirable, as when bugs or malware cause bits to be written at memory locations that were not intended for that purpose by the original software's developer.
However, the most widely used and typical approach used to legitimately modify the low-level instructions of a software program is to edit the program's source code. The altered source code is then recompiled to generate modified low-level instructions, so the changes in program functionality caused by the source code edits will occur the next time the program is executed.